package gbench.sandbox.matlib;

import org.junit.jupiter.api.Test;

import java.util.stream.*;
import java.util.function.*;

import gbench.common.matlib.MatlibCanvas.NVec;
import gbench.common.matlib.MatlibCanvas.Range;
import gbench.common.matlib.data.Pipe;
import gbench.common.matlib.matrix.MatrixOps;
import gbench.common.tree.LittleTree.IRecord;

import static gbench.common.matlib.MatlibCanvas.println;
import static gbench.common.matlib.MatlibCanvas.Range.aaclc;
import static gbench.common.matlib.data.Pipe.PIPE;
import static gbench.common.matlib.matrix.MatrixOps.*;
import static gbench.common.matlib.matrix.MatrixOps.Tuple2.TUP2;
import static gbench.common.matlib.matrix.MatrixOps.Elem.*;

/**
 * 简单的矩操作
 * @author gbench
 *
 */
public class JunitMatrixOps {
    
    /**
     * 矩阵乘法的行求和
     */
    @Test
    public void mmult() {
        println("矩阵乘法的行求和");
        final var lmf = Stream.iterate(0, i->i+1).limit(100)
            .collect(Range.aaclc(aa -> Pipe.PIPE(aa)
                .bind(vt2mx(10, 10))
                .bind(MatrixOps::lmmult).evaluate())
             );// collect
        
        final var x = lmf.apply(NVec.of(10,i->1).mutate(VT(1)));
        println("行求和",x);
    }
    
    /**
     * 矩阵的逆
     */
    @Test
    public void inverse() {
        println("矩阵的逆");
        final var aa = Stream.iterate(0d, i->i+1).limit(36).map(i->Math.random()).collect(mxclc(6,6));
        final var bb = MatrixOps.inverse(aa);
        fmt2(MatrixOps.mmult(aa, bb));
        println("\nschmidt 正交并标准化");
        final var x = MatrixOps.schmidt(aa,true);
        x.forEach(e->println("- ",e));
        println("----------正交矩阵A的:t(A).mmult(A) 获得一个单位矩阵---------------");
        final var p = x.toArray(Double[][]::new);
        fmt2(MatrixOps.mmult(p, MatrixOps.transpose(p)));
    }
    
    /**
     * seq:序列化,lisp CONS 的结构的仿制
     */
    @Test
    public void seq() {
        println("seq:序列化,lisp CONS 的结构的仿制");
        final var seq = SEQ(Stream.iterate(0d, i->i+1).limit(10));
        System.out.println(seq);
        seq.dataS(e->e*2).map(e->e+"\t").forEach(System.out::print);
    }
    
    /**
     * Tuple2操作的演示
     */
    @Test
    public void tup() {
        println("Tuple2操作的演示");
        NVec.of(20,i->i).fmap(e->TUP2(e%5, e)) //  数据按照5进行取模
        .groupBy(e->e._1(),IRecord.ssclc(ss->SEQ(ss.map(Tuple2::_2))),IRecord::REC)
        .foreach((k,v)->{
            println(k,v);
        });
    }
    
    @Test
    public void foo() {
        final Number[][] data = NVec.of(100, i -> i + 1).collect(aaclc(PIPE(vt2mx(10, 10, false))));
        final Number[][] v10x1 = NVec.of(10, i -> i+1).collect(aaclc(PIPE(vt2mx(10, 1, true))));
        final Number[][] v1x10 = NVec.of(10, i -> i+1).collect(aaclc(PIPE(vt2mx(1, 10, true))));
        final BiFunction<Number[][], Number[][], Double[][]> mul = MatrixOps::mmult;
        final Function<Number[][], Number[][]> schmidt = MatrixOps::schmidt2;

        println(MatrixOps.fmt(data));
        println("----------------------------------");
        println(MatrixOps.fmt(PIPE(data).bind(schmidt).get()));
        println("----------------------------------");

        final var p = PIPE(v10x1).bind2(v1x10, mul);
        println(MatrixOps.fmt(p.get()));
        println("----------------------------------");
        println(MatrixOps.fmt(PIPE(data).bind2(NVec.of(10, i -> 1).nx1().toArray(), mul).get()));
        println("nec strides:",NVec.of(10, i -> i).strides());
        println("nvec nxone strides:",NVec.of(10, i -> i).nxone().strides());
    }
}
